﻿/*
 *  DFUtil - a utility for creating and implementing blueprints in Dwarf Fortress.
 *  
 *  Copyright (C) 2009  Katharine Gillis
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/.
*/

using System;
using System.Collections.Generic;
using System.Timers;
using System.Threading;
using System.Windows.Forms;

namespace DFUtil
{
    /// <summary>
    /// Handles all interactions with the Dwarf Fortress application.
    /// </summary>
    public class DFAdapter : Subject
    {
        #region SpecialKeys enumeration

        public enum SpecialKeys {Return, Space, Left, Up, Right, Down, Multiply, Add, Subtract, Divide};

        #endregion

        #region Constants

        private const string DFCLASSNAME = "OpenGL";
        private const string DFTITLE = "Dwarf Fortress";

        #endregion

        #region Variables

        private IntPtr _handle = IntPtr.Zero;
        private System.Timers.Timer _timer;
        private Dictionary<SpecialKeys, uint> _specialKeys;

        #endregion

        #region Properties

        private int _keyDelay;
        /// <summary>
        /// Gets or sets the delay between sending keystrokes, in milliseconds.
        /// </summary>
        public int KeyDelay
        {
            get { return _keyDelay; }
            set
            {
                Properties.Settings.Default["keyDelay"] = value;
                Properties.Settings.Default.Save();
                _keyDelay = value;
            }
        }

        private int _focusDelay;
        /// <summary>
        /// Gets or sets the delay between setting the Dwarf Fortress application as the active
        /// application and starting the blueprint.
        /// </summary>
        public int FocusDelay
        {
            get { return _focusDelay; }
            set
            {
                Properties.Settings.Default["focusDelay"] = value;
                Properties.Settings.Default.Save();
                _focusDelay = value;
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Creates the DFAdapter, which handles interactions with the Dwarf Fortress application.
        /// </summary>
        public DFAdapter()
        {
            if ((int)Properties.Settings.Default["KeyDelay"] != -1)
                _keyDelay = (int)Properties.Settings.Default["KeyDelay"];
            else
                _keyDelay = (int)Properties.Settings.Default["KeyDelayDefault"];

            if ((int)Properties.Settings.Default["FocusDelay"] != -1)
                _focusDelay = (int)Properties.Settings.Default["FocusDelay"];
            else
                _focusDelay = (int)Properties.Settings.Default["FocusDelayDefault"];

            _specialKeys = new Dictionary<SpecialKeys, uint>(10);
            _specialKeys.Add(SpecialKeys.Return, WinAPI.VK_RETURN);
            _specialKeys.Add(SpecialKeys.Space, WinAPI.VK_SPACE);
            _specialKeys.Add(SpecialKeys.Left, WinAPI.VK_LEFT);
            _specialKeys.Add(SpecialKeys.Up, WinAPI.VK_UP);
            _specialKeys.Add(SpecialKeys.Right, WinAPI.VK_RIGHT);
            _specialKeys.Add(SpecialKeys.Down, WinAPI.VK_DOWN);
            _specialKeys.Add(SpecialKeys.Multiply, WinAPI.VK_MULTIPLY);
            _specialKeys.Add(SpecialKeys.Add, WinAPI.VK_ADD);
            _specialKeys.Add(SpecialKeys.Subtract, WinAPI.VK_SUBTRACT);
            _specialKeys.Add(SpecialKeys.Divide, WinAPI.VK_DIVIDE);

            HasHandle();

            _timer = new System.Timers.Timer();
            _timer.AutoReset = true;
            _timer.Interval = 1000;
            _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
            _timer.Start();
        }

        #endregion

        #region Members

        /// <summary>
        /// Checks the status of the handle. If the handle does not initially exist, it will attempt to find the handle.
        /// </summary>
        /// <returns>Returns true if the handle exists, and false if it does not.</returns>
        public bool HasHandle()
        {
            if (_handle == IntPtr.Zero || !WinAPI.IsWindow(_handle))
                _handle = WinAPI.FindWindow(DFCLASSNAME, DFTITLE);

            if (_handle == IntPtr.Zero)
            {
                Notify(false);
                return false;
            }

            Notify(true);
            return true;
        }

        /// <summary>
        /// Sets the Dwarf Fortress application as the active window, then sends the blueprint keys, pausing in between
        /// each key by the number of milliseconds defined in DFAdapter.KeyDelay.
        /// </summary>
        /// <param name="keys">List of keys to send.</param>
        public void Send(List<string> keys)
        {
            WinAPI.SetForegroundWindow(_handle);
            Thread.Sleep(100);
            foreach (string key in keys)
            {
                SendKeys.SendWait(key);
                Thread.Sleep(_keyDelay);
            }
        }

        #endregion

        #region Private members

        // Handles the timer event.
        private void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            HasHandle();
        }

        #endregion
    }
}
